package cn.jiedanba.itext5.gm.sign;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Locale;

import org.bouncycastle.asn1.ASN1GeneralizedTime;
import org.bouncycastle.jcajce.provider.digest.SM3;
import org.ofdrw.gm.ses.v4.SES_Header;
import org.ofdrw.gm.ses.v4.TBS_Sign;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfSignatureAppearance.RenderingMode;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.MakeSignature;

import cn.jiedanba.itext5.BCProvider;
import cn.jiedanba.itext5.gm.sign.signatureContainer.GMExternalSignatureContainer;
import cn.jiedanba.itext5.gm.sign.vo.GetPdfHash;
import cn.jiedanba.itext5.gm.sign.vo.GetPdfHashParamVo;
import cn.jiedanba.itext5.signatureContainer.MyExternalSignatureContainer;

/**
 * 《GB/T 38540-2020 信息安全技术 安全电子签章密码技术规范》 签名
 * 
 */
public class ITextGM extends BCProvider {

	/**
	 * 创建签名域，并获取摘要值
	 * 
	 * @param param
	 */
	public static GetPdfHash getPdfHash(GetPdfHashParamVo param) {
		try {
			ByteArrayOutputStream tmpos = new ByteArrayOutputStream();
			PdfReader reader = new PdfReader(param.getPdf());
			PdfStamper stamper = PdfStamper.createSignature(reader, tmpos, '\0', null, true);
			PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
			appearance.setVisibleSignature(
					new Rectangle(param.getLlx(), param.getLly(), param.getUrx(), param.getUry()), param.getPageNo(),
					appearance.getNewSigName());
			appearance.setSignatureGraphic(
					Image.getInstance(param.getSeal().geteSealInfo().getPicture().getData().getOctets()));
			appearance.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
			appearance.setRenderingMode(RenderingMode.GRAPHIC);
			appearance.setReason(param.getReason());
			appearance.setLocation(param.getLocation());
			GMExternalSignatureContainer signatureContainer = new GMExternalSignatureContainer();
			MakeSignature.signExternalContainer(appearance, signatureContainer, new Integer(40000 * 2 + 2));
			InputStream data = appearance.getRangeStream();
			MessageDigest externalDigest = new SM3.Digest();
			byte digest[] = DigestAlgorithms.digest(data, externalDigest);
			GetPdfHash returnVo = new GetPdfHash();
			returnVo.setDigesHash(digest);
			returnVo.setEmptySignaturePdf(tmpos.toByteArray());
			returnVo.setFieldName(appearance.getFieldName());

			// 组装国密电子签章 签名数据
			TBS_Sign toSign = new TBS_Sign().setVersion(SES_Header.V4).setEseal(param.getSeal())
					.setTimeInfo(new ASN1GeneralizedTime(new Date(), Locale.CHINA)).setDataHash(digest)
					.setPropertyInfo("Signature.xml");
			returnVo.setTBS_Sign(toSign);
			return returnVo;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	/**
	 * 
	 * @param signPdf
	 *            空签名域pdf文件
	 * @param pcks7
	 *            签名数据
	 * @param fieldName
	 *            签名域 标识
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 * @throws GeneralSecurityException
	 */
	public static byte[] signDeferred(byte[] signPdf, byte[] pcks7, String fieldName)
			throws IOException, DocumentException, GeneralSecurityException {
		PdfReader reader = new PdfReader(signPdf);
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		MakeSignature.signDeferred(reader, fieldName, baos, new MyExternalSignatureContainer(pcks7));
		return baos.toByteArray();
	}

}
